package com.bndg.bndggame.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.Chronometer;
import android.widget.TextView;
import android.widget.Toast;

import com.bndg.bndggame.MyApp;
import com.bndg.bndggame.R;
import com.bndg.bndggame.tools.ScreenUtils;
import com.bndg.bndggame.tools.Trace;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;


/**
 * Created by r on 18/3/14.
 */

public class MyViewGroup extends ViewGroup implements View.OnTouchListener {

    private int screenWidth;
    private int screenHeight;
    String TAG = ">>>>";
    /**
     * 存储所有的View，按行记录
     */
    private List<List<View>> mAllViews = new ArrayList<List<View>>();
    /**
     * 记录每一行的最大高度
     */
    private List<Integer> mLineHeight = new ArrayList<Integer>();
    private int layoutWidth;
    private boolean canNext = true;
    private int measuredWidth;
    private Bitmap[] bitmapTiles;
    private int layoutHeight;
    private Bitmap bitmap;

    public void setOverListener(OverListener overListener) {
        this.overListener = overListener;
    }

    private OverListener overListener;

    public void setSquareCount(int squareCount) {
        this.squareCount = squareCount;
    }

    private int squareCount = 3;
    private long moveDuration = 0;
    private int emptyX;
    private int emptyY;
    private boolean isRandomLayout;
    private List<MyRect> rightViewList = new ArrayList<>();
    private boolean canTouch;
    private Chronometer timer;
    private boolean isFirst = true;

    public MyViewGroup(Context context) {
        this(context, null);
    }

    public MyViewGroup(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }


    public void init() {
        canTouch = false;
        maps.clear();
        if (timer != null) {
            timer.stop();
            timer.setBase(SystemClock.elapsedRealtime());//计时器清零
        }
        if (bitmap == null) {
            screenWidth = ScreenUtils.getScreenWidth(MyApp.mContext);
            screenHeight = ScreenUtils.getScreenWidth(MyApp.mContext);
        } else {
            screenWidth = bitmap.getWidth();
            screenHeight = bitmap.getHeight();
            int tileWidth = bitmap.getWidth() / squareCount;
            int tileHeight = bitmap.getHeight() / squareCount;
            Log.d(">>>>", "titleW" + tileWidth);
            Log.d(">>>>", "titleH" + tileHeight);
            bitmapTiles = new Bitmap[squareCount * squareCount];
            int idx = 0;
            for (int i = 0; i < squareCount; i++) {
                for (int j = 0; j < squareCount; j++) {
                    int x = j * tileWidth;
                    int y = i * tileHeight;

                    bitmapTiles[idx++] = Bitmap.createBitmap(bitmap, x, y, tileWidth, tileHeight);
                    Log.d(">>>>", "x====" + x + "y=====" + y + idx);
                }
            }
        }

        for (int i = 1; i < Math.pow(squareCount, 2); i++) {
            TextView textView = new TextView(this.getContext());
            textView.setTextColor(getContext().getResources().getColor(R.color.colorAccent));
            textView.setTextSize(28);
            textView.setGravity(Gravity.CENTER);
            if (bitmap != null && bitmapTiles != null) {
                textView.setBackground(new BitmapDrawable(bitmapTiles[i - 1]));
            } else {
                textView.setText(i + "");
                textView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimary));
            }
            MarginLayoutParams marginLayoutParams = new MarginLayoutParams(screenWidth / squareCount - squareCount * 2, screenHeight / squareCount - squareCount * 2);
            marginLayoutParams.setMargins(1, 1, 1, 1);
            textView.setLayoutParams(marginLayoutParams);
            textView.setOnTouchListener(this);
            addView(textView);
        }
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 获得它的父容器为它设置的测量模式和大小
        Log.d(">>>>", ">>>>>>>>>>>>>on measure");
        int sizeWidth = screenWidth;
        int sizeHeight = screenHeight;
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        Log.e(TAG, sizeWidth + "," + sizeHeight);

        // 如果是warp_content情况下，记录宽和高
        int width = 0;
        int height = 0;
        /**
         * 记录每一行的宽度，width不断取最大宽度
         */
        int lineWidth = 0;
        /**
         * 每一行的高度，累加至height
         */
        int lineHeight = 0;

        int cCount = getChildCount();

        // 遍历每个子元素
        for (int i = 0; i < cCount; i++) {
            View child = getChildAt(i);
            // 测量每一个child的宽和高
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            // 得到child的lp
            MarginLayoutParams lp = (MarginLayoutParams) child
                    .getLayoutParams();
            // 当前子空间实际占据的宽度
            int childWidth = child.getMeasuredWidth() + lp.leftMargin
                    + lp.rightMargin;
            // 当前子空间实际占据的高度
            int childHeight = child.getMeasuredHeight() + lp.topMargin
                    + lp.bottomMargin;
            /**
             * 如果加入当前child，则超出最大宽度，则的到目前最大宽度给width，类加height 然后开启新行
             */
            if (lineWidth + childWidth > sizeWidth) {
                width = Math.max(lineWidth, childWidth);// 取最大的
                lineWidth = childWidth; // 重新开启新行，开始记录
                // 叠加当前高度，
                height += lineHeight;
                // 开启记录下一行的高度
                lineHeight = childHeight;
            } else
            // 否则累加值lineWidth,lineHeight取最大高度
            {
                lineWidth += childWidth;
                lineHeight = Math.max(lineHeight, childHeight);
            }
            // 如果是最后一个，则将当前记录的最大宽度和当前lineWidth做比较
            if (i == cCount - 1) {
                width = Math.max(width, lineWidth);
                height += lineHeight;
            }

        }
        setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth
                : width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight
                : height);
    }

    HashMap<MyRect, Boolean> maps = new HashMap<>();

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        mAllViews.clear();
        mLineHeight.clear();

        int width = getWidth();

        int lineWidth = 0;
        int lineHeight = 0;
        // 存储每一行所有的childView
        List<View> lineViews = new ArrayList<View>();
        int cCount = getChildCount();
        // 遍历所有的孩子
        for (int i = 0; i < cCount; i++) {
            View child = getChildAt(i);
            MarginLayoutParams lp = (MarginLayoutParams) child
                    .getLayoutParams();
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            // 如果已经需要换行
            if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width) {
                // 记录这一行所有的View以及最大高度
                mLineHeight.add(lineHeight);
                // 将当前行的childView保存，然后开启新的ArrayList保存下一行的childView
                mAllViews.add(lineViews);
                lineWidth = 0;// 重置行宽
                lineViews = new ArrayList<View>();
            }
            /**
             * 如果不需要换行，则累加
             */
            lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
            layoutHeight = lineHeight;
            lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
                    + lp.bottomMargin);
            lineViews.add(child);
        }
        // 记录最后一行
        mLineHeight.add(lineHeight);
        mAllViews.add(lineViews);

        int left = 0;
        int top = 0;
        // 得到总行数
        int lineNums = mAllViews.size();
        for (int i = 0; i < lineNums; i++) {
            // 每一行的所有的views
            lineViews = mAllViews.get(i);
            // 当前行的最大高度
            lineHeight = mLineHeight.get(i);

            Log.e(TAG, "第" + i + "行 ：" + lineViews.size() + " , " + lineViews);
            Log.e(TAG, "第" + i + "行， ：" + lineHeight);

            // 遍历当前行所有的View
            for (int j = 0; j < lineViews.size(); j++) {
                View child = lineViews.get(j);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                MarginLayoutParams lp = (MarginLayoutParams) child
                        .getLayoutParams();

                //计算childView的left,top,right,bottom
                int lc = left + lp.leftMargin;
                int tc = top + lp.topMargin;
                int rc = lc + child.getMeasuredWidth();
                int bc = tc + child.getMeasuredHeight();

                child.layout(lc, tc, rc, bc);
                MyRect myRect = new MyRect(lc, tc);
                child.setTag(new MyRect(lc, tc));
                maps.put(myRect, false);

                layoutWidth = child.getMeasuredWidth() + lp.rightMargin
                        + lp.leftMargin;
                left += layoutWidth;
            }
            left = 0;
            top += lineHeight;
        }
        View view = lineViews.get(lineViews.size() - 1);
        //计算childView的left,top,right,bottom
        int lc = view.getLeft() + layoutWidth;
        int tc = view.getTop();
        measuredWidth = view.getMeasuredWidth();
        MyRect myRect = new MyRect(lc, tc);
        emptyX = lc;
        emptyY = tc;
        maps.put(myRect, true);

    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (view.getTag() != null) {
                    if (!canTouch || !canNext) {
                        return true;
                    }
                    MyRect myRect = checkAroundHasEmpty((MyRect) view.getTag(), (int) view.getX(), (int) view.getY());
                    if (myRect != null) {
                        canNext = false;
                        if (myRect.isHorizontal) {
                            if (isRandomLayout) {
                                canNext = true;
                                int layoutX = view.getLeft();
                                int layoutY = view.getTop();
                                int tempWidth = view.getWidth();
                                int tempHeight = view.getHeight();
                                layoutX += myRect.animtionValue;
                                view.layout(layoutX, layoutY, layoutX + tempWidth, layoutY + tempHeight);
                            } else {
                                translationX(view, myRect.animtionValue);
                            }
                        } else {
                            if (isRandomLayout) {
                                canNext = true;
                                int layoutX = view.getLeft();
                                int layoutY = view.getTop();
                                int tempWidth = view.getWidth();
                                int tempHeight = view.getHeight();
                                layoutY += myRect.animtionValue;
                                view.layout(layoutX, layoutY, layoutX + tempWidth, layoutY + tempHeight);
                            } else {
                                translationY(view, myRect.animtionValue);
                            }
                        }
                        if (!isRandomLayout && isFirst) {
                            timer.setBase(SystemClock.elapsedRealtime());//计时器清零
                            timer.start();
                            Trace.d("onTouch: " + "开始");
                            isFirst = false;
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                break;
        }

        return true;
    }

    private void translationX(final View view, final int animtionValue) {
        TranslateAnimation ani = new TranslateAnimation(0, animtionValue, 0, 0);
        ani.setDuration(moveDuration);//设置动画时间
        ani.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                canNext = true;
                int layoutX = view.getLeft();
                int layoutY = view.getTop();
                int tempWidth = view.getWidth();
                int tempHeight = view.getHeight();
                view.clearAnimation();
                layoutX += animtionValue;
                view.layout(layoutX, layoutY, layoutX + tempWidth, layoutY + tempHeight);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        view.startAnimation(ani);
    }

    private void translationY(final View view, final int animtionValue) {
        TranslateAnimation ani = new TranslateAnimation(0, 0, 0, animtionValue);
        ani.setDuration(moveDuration);//设置动画时间
        ani.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                canNext = true;
                int layoutX = view.getLeft();
                int layoutY = view.getTop();
                int tempWidth = view.getWidth();
                int tempHeight = view.getHeight();
                view.clearAnimation();
                layoutY += animtionValue;
                view.layout(layoutX, layoutY, layoutX + tempWidth, layoutY + tempHeight);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        view.startAnimation(ani);
    }

    private MyRect checkAroundHasEmpty(MyRect viewTagRect, int x, int y) {
        for (int i = 0; i < 2; i++) {
            int value = layoutWidth * ((i - 1) == 0 ? 1 : i - 1);
            MyRect moveToRect = new MyRect(x + value, y);
            if (maps.containsKey(moveToRect) && maps.get(moveToRect)) {
                moveToRect.setIsHorizontal(true);
                moveToRect.setAnimtionValue(value);
                maps.put(moveToRect, false);
                maps.put(new MyRect(x, y), true);
                emptyX = x;
                emptyY = y;
                if (!isRandomLayout) {
                    if (viewTagRect.equals(moveToRect)) {
                        rightViewList.add(viewTagRect);
                    } else {
                        rightViewList.remove(viewTagRect);
                    }
                }
                if (rightViewList.size() == Math.pow(squareCount, 2) - 1) {
                    gameOver();
                }
                return moveToRect;
            }
        }

        for (int j = 0; j < 2; j++) {
            int value = layoutHeight * ((j - 1) == 0 ? 1 : j - 1);
            MyRect moveToRect = new MyRect(x, y + value);
            if (maps.containsKey(moveToRect) && maps.get(moveToRect)) {
                moveToRect.setIsHorizontal(false);
                moveToRect.setAnimtionValue(value);
                maps.put(moveToRect, false);
                maps.put(new MyRect(x, y), true);
                if (!isRandomLayout) {
                    if (viewTagRect.equals(moveToRect)) {
                        rightViewList.add(viewTagRect);
                    } else {
                        rightViewList.remove(viewTagRect);
                    }
                }
                if (rightViewList.size() == Math.pow(squareCount, 2) - 1) {
                    gameOver();
                }
                emptyX = x;
                emptyY = y;
                return moveToRect;
            }
        }
        return null;
    }

    private void gameOver() {
        canTouch = false;
        timer.stop();

        if (this.overListener != null) {
            overListener.gameover(getChronometerSeconds(timer));
        }
    }

    public static String getChronometerSeconds(Chronometer cmt) {
        int totalss = 0;
        String string = cmt.getText().toString();
        if (string.length() == 7) {
            String[] split = string.split(":");
            String string2 = split[0];
            int hour = Integer.parseInt(string2);
            int Hours = hour * 3600;
            String string3 = split[1];
            int min = Integer.parseInt(string3);
            int Mins = min * 60;
            int SS = Integer.parseInt(split[2]);
            totalss = Hours + Mins + SS;
            return String.valueOf(totalss);
        } else if (string.length() == 5) {
            String[] split = string.split(":");
            String string3 = split[0];
            int min = Integer.parseInt(string3);
            int Mins = min * 60;
            int SS = Integer.parseInt(split[1]);
            totalss = Mins + SS;
            return String.valueOf(totalss);
        }
        return String.valueOf(totalss);
    }

    public void randomLayout() {
        isFirst = true;
        canTouch = true;
        timer.stop();
        timer.setBase(SystemClock.elapsedRealtime());//计时器清零
        rightViewList.clear();
        isRandomLayout = true;
        moveDuration = 0;
        Random random = new Random();
        for (int i = 1; i < squareCount * squareCount * 10; i++) {
            long downTime = SystemClock.uptimeMillis();
            int rand = random.nextInt(2);
            int x;
            int y;
            if (rand == 0) {
                if (emptyX - layoutWidth < 1) {
                    x = emptyX + layoutWidth;
                    y = emptyY;
                } else if (emptyX + layoutWidth >= getWidth()) {
                    x = emptyX - layoutWidth;
                    y = emptyY;
                } else {
                    x = emptyX + (random.nextInt(2) == 1 ? layoutWidth : -layoutWidth);
                    y = emptyY;
                }
            } else {
                if (emptyY - layoutHeight < 1) {
                    x = emptyX;
                    y = emptyY + layoutHeight;
                } else if (emptyY + layoutHeight >= getHeight()) {
                    x = emptyX;
                    y = emptyY - layoutHeight;
                } else {
                    x = emptyX;
                    y = emptyY + (random.nextInt(2) == 1 ? layoutHeight : -layoutHeight);
                }
            }
            MotionEvent downEvent = MotionEvent.obtain(downTime, downTime,
                    MotionEvent.ACTION_DOWN, x, y, 0);
            dispatchTouchEvent(downEvent);
            downEvent.recycle();

        }
        moveDuration = 0;
        isRandomLayout = false;

        checkRightView();
    }

    private void checkRightView() {
        for (int i = 0; i < getChildCount(); i++) {
            View childAt = getChildAt(i);
            MyRect nowRect = new MyRect((int) childAt.getX(), (int) childAt.getY());
            MyRect viewTagRect = (MyRect) childAt.getTag();
            if (viewTagRect.equals(nowRect)) {
                rightViewList.add(viewTagRect);
            } else {
                rightViewList.remove(viewTagRect);
            }
        }

    }

    public void setTimer(Chronometer timer) {
        this.timer = timer;
    }

    public void setImage(int s) {
        //载入图像，并将图片切成块
        Bitmap back;
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), s);
        back = Bitmap.createScaledBitmap(bitmap, (int) getWidth(), (int) getHeight(), true);
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
    }

    private class MyRect {
        private boolean isHorizontal;
        private int animtionValue;

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        private int x;
        private int y;

        public MyRect(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public void setIsHorizontal(boolean isHorizontal) {
            this.isHorizontal = isHorizontal;
        }

        public void setAnimtionValue(int animtionValue) {
            this.animtionValue = animtionValue;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + x;
            result = prime * result + y;
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (!(obj instanceof MyRect)) {
                return false;
            }
            MyRect other = (MyRect) obj;
            if (x != other.x) {
                return false;
            }
            if (y != other.y) {
                return false;
            }
            return true;
        }
    }

    public interface OverListener {
        void gameover(String time);
    }
}
